package com.biotools.meerkat;

import java.io.*;

public final class Card implements Serializable
{
    public static final int SPADES = 0;
    public static final int HEARTS = 1;
    public static final int DIAMONDS = 2;
    public static final int CLUBS = 3;
    public static final int BAD_CARD = -1;
    public static final int TWO = 0;
    public static final int THREE = 1;
    public static final int FOUR = 2;
    public static final int FIVE = 3;
    public static final int SIX = 4;
    public static final int SEVEN = 5;
    public static final int EIGHT = 6;
    public static final int NINE = 7;
    public static final int TEN = 8;
    public static final int JACK = 9;
    public static final int QUEEN = 10;
    public static final int KING = 11;
    public static final int ACE = 12;
    public static final int NUM_SUITS = 4;
    public static final int NUM_RANKS = 13;
    public static final int NUM_CARDS = 52;
    private int gIndex;
    
    public Card() {
        super();
        this.gIndex = -1;
    }
    
    public Card(final int rank, final int suit) {
        super();
        this.gIndex = toIndex(rank, suit);
    }
    
    public Card(final int index) {
        super();
        if (index >= 0 && index < 52) {
            this.gIndex = index;
        }
        else {
            this.gIndex = -1;
        }
    }
    
    public Card(final String s) {
        super();
        if (s.length() == 2) {
            this.gIndex = this.chars2index(s.charAt(0), s.charAt(1));
        }
    }
    
    public boolean equals(final Card c) {
        return c != null && c.gIndex == this.gIndex;
    }
    
    public Card(final char rank, final char suit) {
        super();
        this.gIndex = this.chars2index(rank, suit);
    }
    
    private int chars2index(final char rank, final char suit) {
        int r = -1;
        r = getRankFromChar(rank);
        int s = -1;
        s = getSuitFromChar(suit);
        if (s != -1 && r != -1) {
            return toIndex(r, s);
        }
        return -1;
    }
    
    public final int getIndex() {
        return this.gIndex;
    }
    
    public void setIndex(final int index) {
        this.gIndex = index;
    }
    
    public static final int toIndex(final int rank, final int suit) {
        return 13 * suit + rank;
    }
    
    public void setCard(final int rank, final int suit) {
        this.gIndex = toIndex(rank, suit);
    }
    
    public final int getRank() {
        return this.gIndex % 13;
    }
    
    public static final int getRank(final int i) {
        return i % 13;
    }
    
    public static final int getSuit(final int i) {
        return i / 13;
    }
    
    public final int getSuit() {
        return this.gIndex / 13;
    }
    
    public String toString() {
        if (this.gIndex < 0) {
            return "??";
        }
        final StringBuffer sb = new StringBuffer(2);
        sb.append(getRankChar(this.getRank()));
        sb.append(getSuitChar(this.getSuit()));
        return sb.toString();
    }
    
    public static int getRankFromChar(final char rank) {
        int r = -1;
        switch (rank) {
            case '2': {
                r = 0;
                break;
            }
            case '3': {
                r = 1;
                break;
            }
            case '4': {
                r = 2;
                break;
            }
            case '5': {
                r = 3;
                break;
            }
            case '6': {
                r = 4;
                break;
            }
            case '7': {
                r = 5;
                break;
            }
            case '8': {
                r = 6;
                break;
            }
            case '9': {
                r = 7;
                break;
            }
            case 'T':
            case 't': {
                r = 8;
                break;
            }
            case 'J':
            case 'j': {
                r = 9;
                break;
            }
            case 'Q':
            case 'q': {
                r = 10;
                break;
            }
            case 'K':
            case 'k': {
                r = 11;
                break;
            }
            case 'A':
            case 'a': {
                r = 12;
                break;
            }
        }
        return r;
    }
    
    public static int getSuitFromChar(final char suit) {
        int s = -1;
        switch (suit) {
            case 'h': {
                s = 1;
                break;
            }
            case 'd': {
                s = 2;
                break;
            }
            case 's': {
                s = 0;
                break;
            }
            case 'c': {
                s = 3;
                break;
            }
            case 'H': {
                s = 1;
                break;
            }
            case 'D': {
                s = 2;
                break;
            }
            case 'S': {
                s = 0;
                break;
            }
            case 'C': {
                s = 3;
                break;
            }
        }
        return s;
    }
    
    public static char getRankChar(final int r) {
        char s = '\0';
        switch (r) {
            case 12: {
                s = 'A';
                break;
            }
            case 11: {
                s = 'K';
                break;
            }
            case 10: {
                s = 'Q';
                break;
            }
            case 9: {
                s = 'J';
                break;
            }
            case 8: {
                s = 'T';
                break;
            }
            default: {
                s = Character.forDigit(r + 2, 36);
                break;
            }
        }
        return s;
    }
    
    public static char getSuitChar(final int s) {
        char c = '*';
        switch (s) {
            case 1: {
                c = 'h';
                break;
            }
            case 2: {
                c = 'd';
                break;
            }
            case 3: {
                c = 'c';
                break;
            }
            case 0: {
                c = 's';
                break;
            }
        }
        return c;
    }
    
    public boolean valid() {
        return this.gIndex >= 0 && this.gIndex < 52;
    }
}
